<!--
 * @Author: 徐建辰
 * @Date: 2022-06-06 10:00:56
 * @LastEditTime: 2022-06-06 10:05:52
 * @LastEditors: 徐建辰
 * @Description: 数字动画组件
-->
<template>
  <div class="count-to-wrapper">
    <slot name="left"/>
    <p class="content-outer">
      <span ref="countupRef" :class="['count-to-count-text', 'ordinary', countClass]" :id="counterId">123</span>
      <i :class="['count-to-unit-text', unitClass]">{{ unitText }}</i>
    </p>
    <slot name="right"/>
  </div>
</template>

<script setup>
import {ref, watch, computed, onMounted, nextTick, getCurrentInstance} from 'vue'
import {CountUp} from 'countup.js'

// eslint-disable-next-line
const props = defineProps({
  init: {
    type: Number,
    default: 0
  },
  /**
   * @description 起始值，即动画开始前显示的数值
   */
  startVal: {
    type: Number,
    default:1110
  },
  /**
   * @description 结束值，即动画结束后显示的数值
   */
  end: {
    type: Number,
    required: true
  },
  /**
   * @description 保留几位小数
   */
  decimals: {
    type: Number,
    default: 0
  },
  /**
   * @description 分隔整数和小数的符号，默认是小数点
   */
  decimal: {
    type: String,
    default: '.'
  },
  /**
   * @description 动画持续的时间，单位是秒
   */
  duration: {
    type: Number,
    default: 2
  },
  /**
   * @description 动画延迟开始的时间，单位是秒
   */
  delay: {
    type: Number,
    default: 0
  },
  /**
   * @description 是否禁用easing动画效果
   */
  uneasing: {
    type: Boolean,
    default: false
  },
  /**
   * @description 是否使用分组，分组后每三位会用一个符号分隔
   */
  useGroup: {
    type: Boolean,
    default: false
  },
  /**
   * @description 用于分组(useGroup)的符号
   */
  separator: {
    type: String,
    default: ','
  },
  /**
   * @description 是否简化显示，设为true后会使用unit单位来做相关省略
   */
  simplify: {
    type: Boolean,
    default: false
  },
  /**
   * @description 自定义单位，如[3, 'K+'], [6, 'M+']即大于3位数小于6位数的用k+来做省略
   *              1000即显示为1K+
   */
  unit: {
    type: Array,
    default () {
      return [[3, 'K+'], [6, 'M+'], [9, 'B+']]
    }
  },
  countClass: {
    type: String,
    default: ''
  },
  unitClass: {
    type: String,
    default: ''
  }
})

const countupRef = ref(null)
const counter = ref(null)
const unitText = ref('')

const counterId = computed(() => `count_to_${getCurrentInstance().uid}`)

onMounted(async () => {
  await nextTick()
  const p = props
  const endVal = getValue(p.end)
  counter.value = new CountUp(countupRef.value, p.end, endVal, p.decimals, p.duration, {
    useEasing: !p.uneasing,
    useGrouping: p.useGroup,
    separator: p.separator,
    decimal: p.decimal
  })
  setTimeout(() => {
    if (!counter.value.error) counter.value.start()
  }, p.delay)
})

watch(() => props.end, newVal => {
  const endVal = getValue(newVal)
  counter.value.update(endVal)
})

function getHandleVal (val, len) {
  const p = props
  return {
    endVal: parseInt(val / Math.pow(10, p.unit[len - 1][0]), 10),
    unitText: p.unit[len - 1][1]
  }
}
function transformValue (val) {
  const p = props
  const len = p.unit.length
  let res = {
    endVal: 0,
    unitText: ''
  }
  if (val < Math.pow(10, this.unit[0][0])) res.endVal = val
  else {
    for (let i = 1; i < len; i++) {
      if (val >= Math.pow(10, p.unit[i - 1][0]) && val < Math.pow(10, p.unit[i][0])) res = getHandleVal(val, i)
    }
  }
  if (val > Math.pow(10, p.unit[len - 1][0])) res = getHandleVal(val, len)
  return res
}
function getValue (val) {
  const p = props
      let res = 0
      if (p.simplify) {
        const {endVal, unitText: unitData } = transformValue(val)
        unitText.value = unitData
        res = endVal
      } else {
        res = val
      }
      return res
    }
</script>

<style scoped lang="scss">
.count-to-wrapper{
  .content-outer{
    display: inline-block;
    .ordinary {
      font-size: 24px;
      color: #333;
    }
    .count-to-unit-text{
      font-style: normal;
    }
  }
}
</style>
